package org.dicr.util.jds.conn.gui;

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import javax.swing.*;

import org.dicr.event.*;
import org.dicr.gui.*;
import org.dicr.gui.layout.*;
import org.dicr.util.jds.conn.*;

import com.borland.dx.sql.dataset.*;

/***********************************************************************************************************************
 * панель свойств соединения.
 * 
 * @author Igor A Tarasov me@dicr.dn.ua
 * @version 030113
 **********************************************************************************************************************/
public class ConnectionElementPanel extends JPanel implements DicrDialogContent {
	private static final long serialVersionUID = -1554615542511935057L;

	ConnectionElement element = null;

	private JLabel nameLabel = new JLabel("Название:");

	private JTextField nameText = new JTextField();

	private JLabel driverLabel = new JLabel("Драйвер:");

	private JTextField driverText = new JTextField();

	private JLabel typeLabel = new JLabel("Тип:");

	JComboBox typeCombo = new JComboBox(new String[] { "Локально", "Удаленно" });

	private JLabel serverLabel = new JLabel("Сервер:");

	private JTextField serverText = new JTextField();

	private JLabel fileLabel = new JLabel("Файл:");

	JTextField fileText = new JTextField();

	JButton fileButton = new JButton("...");

	private JLabel userLabel = new JLabel("Логин:");

	private JTextField userText = new JTextField();

	private JLabel passLabel = new JLabel("Пароль:");

	private JPasswordField passText = new JPasswordField();

	private JButton propButton = new JButton("Параметры");

	JButton testButton = new JButton("Тест соединения...");

	private ComponentsActionListener comlis = new ComponentsActionListener();

	boolean ignoreActions = false;

	/*******************************************************************************************************************
	 * Конструктор
	 * 
	 * @param elem connection element
	 ******************************************************************************************************************/
	public ConnectionElementPanel(ConnectionElement elem) {
		try {
			jbInit(elem);
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
	}

	/*******************************************************************************************************************
	 * Конструктор
	 ******************************************************************************************************************/
	public ConnectionElementPanel() {
		this(null);
	}

	/*******************************************************************************************************************
	 * Инициализация
	 ******************************************************************************************************************/
	private void jbInit(ConnectionElement elem) {
		this.setLayout(new PnutsLayout(3, 5, 2));
		this.add(this.nameLabel, "halign=left");
		this.add(this.nameText, "halign=fill, expand=x, colspan=2");
		this.add(new JSeparator(SwingConstants.HORIZONTAL), "halign=fill, expand=x, colspan=3, pady=10");
		this.add(this.driverLabel, "halign=left");
		this.add(this.driverText, "halign=fill, expand=x, colspan=2");
		this.add(this.typeLabel, "halign=left");
		this.add(this.typeCombo, "halign=fill, expand=x, colspan=2");
		this.add(this.serverLabel, "halign=left");
		this.add(this.serverText, "halign=fill, expand=x, colspan=2");
		this.add(this.fileLabel, "halign=left");
		JPanel tmpPanel = new JPanel(new BorderLayout());
		tmpPanel.add(this.fileText, BorderLayout.CENTER);
		tmpPanel.add(this.fileButton, BorderLayout.EAST);
		this.add(tmpPanel, "halign=fill, expand=x, colspan=2");
		this.add(new JSeparator(SwingConstants.HORIZONTAL), "halign=fill, expand=x, colspan=3, pady=5");
		this.add(this.userLabel, "halign=left");
		this.add(this.userText, "halign=fill, expand=x, colspan=2");
		this.add(this.passLabel, "halign=left");
		this.add(this.passText, "halign=fill, expand=x, colspan=2");
		this.add(new JSeparator(SwingConstants.HORIZONTAL), "halign=fill, expand=x, colspan=3, pady=5");
		this.add(Box.createHorizontalStrut(1));
		this.add(this.propButton, "halign=fill, expand=x");
		this.add(this.testButton, "halign=fill, expand=x");
		this.nameText.setToolTipText("Название соединения");
		this.nameText.addActionListener(this.comlis);
		this.driverText.setToolTipText("Используемый драйвер базы данных");
		this.driverText.setEditable(false);
		this.driverText.addActionListener(this.comlis);
		this.typeCombo.setToolTipText("Подключение к файлу на локальном диске или к SQL-серверу");
		this.typeCombo.addActionListener(this.comlis);
		this.serverLabel.setEnabled(false);
		this.serverText.setToolTipText("Сервер баз данных");
		this.serverText.addActionListener(this.comlis);
		this.serverText.setEnabled(false);
		this.fileText.setToolTipText("Файл базы данных на локальном компьютере или на сервере");
		this.fileText.setColumns(20);
		this.fileText.addActionListener(this.comlis);
		this.fileButton.setToolTipText("Выбор файла на локальном компьютере");
		this.fileButton.setMargin(this.fileText.getMargin());
		this.fileButton.addActionListener(this.comlis);
		this.userText.setToolTipText("Логин пользователя на подключения к базе данных");
		this.userText.addActionListener(this.comlis);
		this.passText.setToolTipText("Пароль пользователя (иногда можно не заполнять)");
		this.passText.addActionListener(this.comlis);
		this.propButton.setToolTipText("Дополнительные параметры соединения");
		this.propButton.addActionListener(this.comlis);
		this.propButton.setEnabled(false);
		this.testButton.setToolTipText("Проверка подключения к базе данных");
		this.testButton.addActionListener(this.comlis);
		this.setConnectionElement((elem == null) ? new ConnectionElement() : elem);
	}

	/*******************************************************************************************************************
	 * Обновление описателя соединения
	 ******************************************************************************************************************/
	protected void updateConnection() {
		if (this.element == null) return;
		this.element.setName(this.nameText.getText());
		ConnectionDescriptor desc = this.element.getDescriptor();
		if (desc == null) this.element.setDescriptor(desc = new ConnectionDescriptor(""));
		desc.setDriver(this.driverText.getText());
		desc.setConnectionURL(new DataStoreURL(this.typeCombo.getSelectedIndex() == 0, this.serverText.getText(),
		        this.fileText.getText()).getURL());
		desc.setUserName(this.userText.getText());
		desc.setPassword(new String(this.passText.getPassword()));
	}

	/*******************************************************************************************************************
	 * Обновляет элементы типа соединения
	 ******************************************************************************************************************/
	protected void updateTypeControls() {
		try {
			this.ignoreActions = true;
			boolean remote = this.typeCombo.getSelectedIndex() == 1;
			this.serverLabel.setEnabled(remote);
			this.serverText.setEnabled(remote);
			this.serverText.setEditable(remote);
			this.fileButton.setEnabled(!remote);
		} finally {
			this.ignoreActions = false;
		}
	}

	/*******************************************************************************************************************
	 * Обновляет элементы управления
	 ******************************************************************************************************************/
	protected void updateControls() {
		try {
			this.ignoreActions = true;
			if (this.element == null) return;
			this.nameText.setText(this.element.getName() != null ? this.element.getName() : "Соединение");
			ConnectionDescriptor desc = this.element.getDescriptor();
			if (desc == null) this.element.setDescriptor(desc = new ConnectionDescriptor(""));
			this.driverText.setText(desc.getDriver() != null ? desc.getDriver()
			        : "com.borland.datastore.jdbc.DataStoreDriver");
			DataStoreURL url = new DataStoreURL(desc.getConnectionURL());
			this.typeCombo.setSelectedIndex(url.isLocal() ? 0 : 1);
			this.serverText.setText(url.getServer());
			this.fileText.setText(url.getFile());
			this.userText.setText(desc.getUserName() != null ? desc.getUserName() : "username");
			this.passText.setText(desc.getPassword() != null ? desc.getPassword() : "password");
		} finally {
			this.ignoreActions = false;
		}
		updateTypeControls();
	}

	/*******************************************************************************************************************
	 * Установка элемента соединения
	 * 
	 * @param elem connection element
	 ******************************************************************************************************************/
	public void setConnectionElement(ConnectionElement elem) {
		if (this.element != elem) {
			this.element = elem;
			updateControls();
		}
	}

	/*******************************************************************************************************************
	 * Возвращает элемент соединения
	 * 
	 * @return connection element
	 ******************************************************************************************************************/
	public ConnectionElement getConnectionElement() {
		updateConnection();
		return this.element;
	}

	/*******************************************************************************************************************
	 * ######################################################################### Слушатель событий компонентов
	 * #########################################################################
	 ******************************************************************************************************************/
	class ComponentsActionListener implements ActionListener {
		/**
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		@Override
        public void actionPerformed(ActionEvent e) {
			if (ConnectionElementPanel.this.ignoreActions) return;
			Object src = e.getSource();
			if (src == ConnectionElementPanel.this.typeCombo) {
				updateTypeControls();
				updateConnection();
			} else if (src == ConnectionElementPanel.this.fileButton) {
				CustomFileFilter filter = new CustomFileFilter();
				filter.setDescription(".jds - файлы баз данных DataStore");
				filter.addExt("jds");

				String filename = ConnectionElementPanel.this.fileText.getText().trim();
				if (filename.length() < 1) filename = null;

				JFileChooser chooser = new JFileChooser();
				chooser.setAcceptAllFileFilterUsed(true);
				chooser.setDialogTitle("Выберите файл базы данных");
				chooser.setDialogType(JFileChooser.OPEN_DIALOG);
				chooser.setApproveButtonText("Принять");
				chooser.setFileFilter(filter);
				chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
				if (filename != null) chooser.setSelectedFile(new File(filename));
				while (chooser.showOpenDialog(ConnectionElementPanel.this) == JFileChooser.APPROVE_OPTION) {
					File file = chooser.getSelectedFile();
					if (file != null) {
						if (!file.exists()) {
							JOptionPane.showMessageDialog(ConnectionElementPanel.this, "Файл не существует: "
							        + file.getPath(), "Ошибка открытия файла", JOptionPane.ERROR_MESSAGE);
						} else {
							ConnectionElementPanel.this.fileText.setText(file.getPath());
							updateConnection();
							break;
						}
					}
				}
			} else if (src == ConnectionElementPanel.this.testButton) {
				if (ConnectionElementPanel.this.element != null) try {
					updateConnection();
					Database database = new Database();
					database.setConnection(ConnectionElementPanel.this.element.getDescriptor());
					database.openConnection();
					database.closeConnection();
					database.setConnection(null);
					JOptionPane.showMessageDialog(ConnectionElementPanel.this, "Тест соединения прошел успешно.",
					        "Тест соединения", JOptionPane.INFORMATION_MESSAGE);
				} catch (Throwable th) {
					DicrExceptionHandler.handleException(th, this, true);
				}
			}
			updateConnection();
		}
	}

	/*******************************************************************************************************************
	 * Создает диалоговое окно
	 * 
	 * @param parent parent dialog
	 * @param elem element to edit
	 * @return created dialog
	 ******************************************************************************************************************/
	public DicrDialog createDialog(Component parent, ConnectionElement elem) {
		if (elem != null) this.setConnectionElement(elem);
		return new DicrDialog(parent, "Свойства соединения '" + this.element.getName() + "'", DicrDialog.DIALOG_YES_NO,
		        this);
	}

	/*******************************************************************************************************************
	 * Выводит диалогое окно. Возвращает ConnectionElement в случае принятия или null в случае отмены.
	 * 
	 * @param parent parent component
	 * @param elem element to edit
	 * @return edited element
	 ******************************************************************************************************************/
	public ConnectionElement showEditDialog(Component parent, ConnectionElement elem) {
		DicrDialog dialog = createDialog(parent, elem);
		dialog.setVisible(true);
		this.setConnectionElement(null);
		return dialog.isAccepted() ? getConnectionElement() : null;
	}

	/*******************************************************************************************************************
	 * Выводит диалогое окно. Возвращает ConnectionElement в случае принятия или null в случае отмены.
	 * 
	 * @param parent parent dialog
	 * @return connection element
	 ******************************************************************************************************************/
	public ConnectionElement showEditDialog(Component parent) {
		return showEditDialog(parent, null);
	}

	/**
	 * @see org.dicr.gui.DicrDialogContent#addContentListener(org.dicr.event.ProgramListener)
	 */
	@Override
    public void addContentListener(ProgramListener l) {
	// NOP
	}

	/**
	 * @see org.dicr.gui.DicrDialogContent#removeContentListener(org.dicr.event.ProgramListener)
	 */
	@Override
    public void removeContentListener(ProgramListener l) {
	// NOP
	}

	/*******************************************************************************************************************
	 * Освобождение ресурсов панели при закрытии окна
	 ******************************************************************************************************************/
	@Override
    public void shutdown() {
		this.setConnectionElement(null);
	}
}
